package entity

import (
	"time"

	"gitee.com/chenhonghua/ginorigin/database"
	"gorm.io/gorm"
)

type Exercise struct {
	Id          int       `json:"id" gorm:"primary_key;auto_increment;column:id;comment:'题目ID'"`
	CreatedTime time.Time `json:"created_time" gorm:"column:created_time;default:CURRENT_TIMESTAMP;comment:'创建时间'"`
	UpdatedTime time.Time `json:"updated_time" gorm:"column:updated_time;default:CURRENT_TIMESTAMP;comment:'更新时间'"`
	State       State     `json:"state" gorm:"column:state;default:0;comment:'状态'"`
	Type        Type      `json:"type" gorm:"column:type;comment:'种类'"`
	Subject     Subject   `json:"subject" gorm:"column:subject;comment:'学科'"`
	Content     string    `json:"content" gorm:"column:content;comment:'内容'"`
	Analysis    string    `json:"analysis" gorm:"column:analysis;comment:'解析'"`
	Answer      string    `json:"answer" gorm:"column:answer;comment:'题目答案'"`

	Options []Option `json:"options" gorm:"foreignKey:ExerciseId;references:Id;comment:'选项'"`
}

type Option struct {
	Id          int       `json:"id" gorm:"primary_key;auto_increment;column:id;comment:'选项ID'"`
	CreatedTime time.Time `json:"created_time" gorm:"column:created_time;default:CURRENT_TIMESTAMP;comment:'创建时间'"`
	ExerciseId  int       `json:"-" gorm:"column:exercise_id;comment:'题目ID'"`
	Sequence    int       `json:"sequence" gorm:"column:sequence;comment:'选项序号'"`
	Content     string    `json:"content" gorm:"column:content;comment:'选项内容'"`
}

func (exec *Exercise) Create() error {
	return database.GetConnection().Transaction(func(tx *gorm.DB) error {
		options := exec.Options
		exec.Options = nil
		if e := tx.Model(&Exercise{}).Create(&exec).Error; e != nil {
			return e
		} else if len(options) > 0 {
			for i, option := range options {
				option.ExerciseId = exec.Id
				option.Sequence = i
				if e := tx.Model(&Option{}).Create(&option).Error; e != nil {
					return e
				}
			}
		}
		return nil
	})
}

func (exec *Exercise) UpdateState(state State) error {
	return database.GetConnection().Model(&Exercise{}).Where("id", exec.Id).Update("state", state).Error
}

func (exec *Exercise) Update() error {
	exec.UpdatedTime = time.Now()
	return database.GetConnection().Transaction(func(tx *gorm.DB) error {
		options := exec.Options
		exec.Options = nil
		if e := tx.Model(&Exercise{}).Where("id", exec.Id).Updates(&exec).Error; e != nil {
			return e
		} else if len(options) > 0 {
			if e := tx.Model(&Option{}).Where("exercise_id", exec.Id).Delete(&Option{}).Error; e != nil {
				return e
			}
			for i, option := range options {
				option.ExerciseId = exec.Id
				option.Sequence = i
				if e := tx.Model(&Option{}).Create(&option).Error; e != nil {
					return e
				}
			}
		}
		return nil
	})
}

func (exec *Exercise) Delete() error {
	return exec.UpdateState(Deleted)
}

func (exec *Exercise) DeleteFromDisk() error {
	return database.GetConnection().Transaction(func(tx *gorm.DB) error {
		if e := tx.Model(&Exercise{}).Where("id", exec.Id).Delete(&exec).Error; e != nil {
			return e
		} else if e := tx.Model(&Option{}).Where("exercise_id", exec.Id).Delete(&Option{}).Error; e != nil {
			return e
		}
		return nil
	})
}

func FindAll(states ...State) (execises []Exercise, e error) {
	tx := database.GetConnection().Model(&Exercise{})
	if len(states) > 0 {
		tx = tx.Where("state in ?", states)
	}
	if e = tx.Preload("Options").Find(&execises).Error; e != nil {
		return nil, e
	}
	return execises, nil
}
